<%--
  Created by IntelliJ IDEA.
  User: 哦耶
  Date: 2025/11/9
  Time: 12:53
  To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>API调试中心</title>
  <!-- 引入Bootstrap CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
  <!-- 引入Font Awesome -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
  <style>
    :root {
      --primary-color: #667eea;
      --primary-dark: #5a67d8;
      --secondary-color: #764ba2;
      --success-color: #10b981;
      --warning-color: #f59e0b;
      --danger-color: #ef4444;
      --bg-light: #f8f9fa;
      --bg-white: #ffffff;
      --text-dark: #2d3748;
      --text-light: #6b7280;
      --border-color: #e5e7eb;
      --shadow-light: 0 4px 20px rgba(0,0,0,0.08);
      --shadow-medium: 0 8px 30px rgba(0,0,0,0.12);
    }

    body {
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      font-family: 'Segoe UI', 'Microsoft YaHei', Arial, sans-serif;
      padding-top: 0;
      min-height: 100vh;
    }

    .container {
      max-width: 1400px;
    }

    .header {
      background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
      color: white;
      padding: 50px 0;
      margin-bottom: 40px;
      border-bottom: none;
      box-shadow: 0 4px 20px rgba(0,0,0,0.1);
      position: relative;
      overflow: hidden;
    }

    .header::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="1"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
    }

    .header h1 {
      font-size: 2.5rem;
      font-weight: 700;
      margin-bottom: 10px;
      text-shadow: 0 2px 10px rgba(0,0,0,0.2);
      position: relative;
    }

    .api-title {
      font-size: 1.4rem;
      font-weight: 600;
      margin-bottom: 25px;
      color: var(--text-dark);
      padding-bottom: 15px;
      border-bottom: 2px solid var(--primary-color);
      display: inline-block;
    }

    .card {
      border: none;
      border-radius: 15px;
      box-shadow: var(--shadow-light);
      margin-bottom: 30px;
      background: var(--bg-white);
      overflow: hidden;
      transition: transform 0.3s ease, box-shadow 0.3s ease;
    }

    .card:hover {
      transform: translateY(-5px);
      box-shadow: var(--shadow-medium);
    }

    .card-body {
      padding: 30px;
    }

    .nav-tabs {
      border-bottom: 2px solid var(--border-color);
      margin-bottom: 30px;
    }

    .nav-link {
      border: none;
      border-radius: 8px 8px 0 0;
      padding: 15px 25px;
      font-weight: 500;
      color: var(--text-light);
      transition: all 0.3s ease;
      margin-right: 5px;
      background: var(--bg-light);
    }

    .nav-link:hover {
      color: var(--primary-color);
      background: rgba(102, 126, 234, 0.1);
    }

    .nav-link.active {
      background: var(--primary-color);
      color: white;
      border: none;
      box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3);
    }

    .form-group {
      margin-bottom: 25px;
    }

    .form-control {
      border: 2px solid var(--border-color);
      border-radius: 8px;
      padding: 12px 15px;
      font-size: 1rem;
      transition: all 0.3s ease;
    }

    .form-control:focus {
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
    }

    .btn-primary {
      background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
      border: none;
      border-radius: 8px;
      padding: 12px 30px;
      font-weight: 600;
      font-size: 1rem;
      transition: all 0.3s ease;
      box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
    }

    .btn-primary:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
      background: linear-gradient(135deg, var(--primary-dark) 0%, var(--secondary-color) 100%);
    }

    .result-container {
      background: var(--bg-white);
      border: 2px solid var(--border-color);
      border-radius: 10px;
      padding: 25px;
      max-height: 600px;
      overflow-y: auto;
      font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
      font-size: 0.9rem;
      line-height: 1.5;
    }

    .alert {
      border: none;
      border-radius: 10px;
      padding: 20px;
      margin-bottom: 20px;
      font-weight: 500;
    }

    .alert-info {
      background: linear-gradient(135deg, #dbeafe 0%, #eff6ff 100%);
      color: #1e40af;
      border-left: 4px solid #3b82f6;
    }

    .alert-danger {
      background: linear-gradient(135deg, #fee2e2 0%, #fef2f2 100%);
      color: #dc2626;
      border-left: 4px solid #ef4444;
    }

    .alert-warning {
      background: linear-gradient(135deg, #fef3c7 0%, #fffbeb 100%);
      color: #d97706;
      border-left: 4px solid #f59e0b;
    }

    .alert-success {
      background: linear-gradient(135deg, #d1fae5 0%, #ecfdf5 100%);
      color: #065f46;
      border-left: 4px solid #10b981;
    }

    .spinner {
      display: inline-block;
      width: 25px;
      height: 25px;
      border: 3px solid rgba(102, 126, 234, 0.3);
      border-radius: 50%;
      border-top-color: var(--primary-color);
      animation: spin 1s ease-in-out infinite;
      margin-right: 10px;
    }

    @keyframes spin {
      to { transform: rotate(360deg); }
    }

    /* JSON语法高亮样式优化 */
    pre {
      background: transparent !important;
      border: none !important;
      margin: 0 !important;
      font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
      line-height: 1.6;
    }

    .string { color: #ce9178; font-weight: 500; }
    .number { color: #b5cea8; font-weight: 600; }
    .boolean { color: #569cd6; font-weight: 600; }
    .null { color: #569cd6; font-weight: 600; }

    /* 响应式设计 */
    @media (max-width: 768px) {
      .header {
        padding: 30px 0;
      }

      .header h1 {
        font-size: 2rem;
      }

      .card-body {
        padding: 20px;
      }

      .nav-link {
        padding: 12px 20px;
        font-size: 0.9rem;
      }

      .result-container {
        padding: 15px;
        max-height: 400px;
      }
    }

    /* 滚动条样式 */
    .result-container::-webkit-scrollbar {
      width: 8px;
    }

    .result-container::-webkit-scrollbar-track {
      background: var(--bg-light);
      border-radius: 4px;
    }

    .result-container::-webkit-scrollbar-thumb {
      background: var(--primary-color);
      border-radius: 4px;
    }

    .result-container::-webkit-scrollbar-thumb:hover {
      background: var(--primary-dark);
    }
  </style>

</head>
<body>
<div class="header">
  <div class="container">
    <h1><i class="fas fa-tools"></i> API调试中心</h1>
  </div>
</div>

<div class="container">
  <div class="card">
    <div class="card-body">
      <!-- 标签页导航 -->
      <ul class="nav nav-tabs" id="apiTabs">
        <li class="nav-item">
          <a class="nav-link active" id="user-role-tab" data-bs-toggle="tab" href="#user-role">
            <i class="fa fa-user-circle-o"></i> 查询用户角色
          </a>
        </li>
        <li class="nav-item">
          <a class="nav-link" id="role-menu-tab" data-bs-toggle="tab" href="#role-menu">
            <i class="fa fa-list-alt"></i> 查询角色菜单
          </a>
        </li>
        <li class="nav-item">
          <a class="nav-link" id="users-search-tab" data-bs-toggle="tab" href="#users-search">
            <i class="fa fa-search"></i> 多条件查询用户
          </a>
        </li>
      </ul>

      <!-- 标签页内容 -->
      <div class="tab-content">
        <!-- 任务一：查询用户及角色 -->
        <div class="tab-pane fade show active" id="user-role">
          <div class="api-title">
            <i class="fa fa-user-circle-o fa-lg"></i> 查询特定用户的所有角色
          </div>
          <form id="userRoleForm">
            <div class="form-group">
              <label for="loginname">用户名 (loginname):</label>
              <input type="text" class="form-control" id="loginname" placeholder="请输入用户名" required>
            </div>
            <button type="submit" class="btn btn-primary">
              <i class="fa fa-search"></i> 查询
            </button>
          </form>
          <div class="result-container mt-4" id="userRoleResult"></div>
        </div>

        <!-- 任务二：查询角色及菜单 -->
        <div class="tab-pane fade" id="role-menu">
          <div class="api-title">
            <i class="fa fa-list-alt fa-lg"></i> 查询特定角色的所有菜单权限
          </div>
          <form id="roleMenuForm">
            <div class="form-group">
              <label for="roleId">角色ID (选填):</label>
              <input type="number" class="form-control" id="roleId" placeholder="请输入角色ID">
            </div>
            <div class="form-group">
              <label for="roleName">角色名称 (选填):</label>
              <input type="text" class="form-control" id="roleName" placeholder="请输入角色名称">
            </div>
            <div class="alert alert-info" role="alert">
              <i class="fa fa-info-circle"></i> 提示：请至少输入角色ID或角色名称其中一项
            </div>
            <button type="submit" class="btn btn-primary">
              <i class="fa fa-search"></i> 查询
            </button>
          </form>
          <div class="result-container mt-4" id="roleMenuResult"></div>
        </div>

        <!-- 任务三：多条件查询用户及权限 -->
        <div class="tab-pane fade" id="users-search">
          <div class="api-title">
            <i class="fa fa-search fa-lg"></i> 多条件查询用户与其所有权限
          </div>
          <form id="usersSearchForm">
            <div class="form-row">
              <div class="form-group col-md-4">
                <label for="usersSearchLoginname">用户名:</label>
                <input type="text" class="form-control" id="usersSearchLoginname" placeholder="用户名">
              </div>
              <div class="form-group col-md-4">
                <label for="usersSearchEmail">邮箱:</label>
                <input type="text" class="form-control" id="usersSearchEmail" placeholder="邮箱">
              </div>
              <div class="form-group col-md-4">
                <label for="usersSearchStatus">状态:</label>
                <select class="form-control" id="usersSearchStatus">
                  <option value="">全部</option>
                  <option value="1">启用</option>
                  <option value="0">禁用</option>
                </select>
              </div>
            </div>
            <button type="submit" class="btn btn-primary">
              <i class="fa fa-search"></i> 多条件查询
            </button>
          </form>
          <div class="result-container mt-4" id="usersSearchResult"></div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- 引入Bootstrap JS和jQuery -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
  // 通用API调用函数 - 改进版
  // 通用API调用函数 - 改进版
  function callApi(url, method, data, resultElement) {
    // 显示加载状态
    $(resultElement).html('<div class="spinner"></div> 正在请求数据...');

    $.ajax({
      url: url,
      type: method,
      data: data,
      // 添加headers设置，明确告诉服务器我们可以接受JSON格式的响应
      headers: {
        'Accept': 'application/json, text/javascript, */*; q=0.01'
      },
      // 移除dataType: 'json'，让jQuery自动判断响应类型
      success: function(response, status, xhr) {
        // 格式化JSON显示结果
        try {
          // 确保响应是JSON格式
          let jsonResponse = typeof response === 'string' ? JSON.parse(response) : response;
          $(resultElement).html(syntaxHighlight(JSON.stringify(jsonResponse, null, 2)));
        } catch (e) {
          // 非JSON响应的处理
          $(resultElement).html('<div class="alert alert-info">响应不是JSON格式: <pre>' + response + '</pre></div>');
        }
      },
      error: function(xhr, status, error) {
        // 改进错误处理
        let errorMsg = '<div class="alert alert-danger">';
        errorMsg += '<strong>请求失败:</strong> ' + status + '<br>';
        errorMsg += '<strong>状态码:</strong> ' + xhr.status + '<br>';

        if (xhr.responseText) {
          errorMsg += '<strong>响应内容:</strong><br>';
          // 尝试以纯文本形式显示错误响应，避免解析错误
          errorMsg += '<pre style="white-space: pre-wrap; word-break: break-word;">' + escapeHtml(xhr.responseText) + '</pre>';
        }

        errorMsg += '</div>';
        $(resultElement).html(errorMsg);
      }
    });
  }
  // HTML转义函数，防止XSS和显示问题
  function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }

  // JSON语法高亮函数
  function syntaxHighlight(json) {
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return '<pre>' + json.replace(/("(\u[a-zA-Z0-9]{4}|[^"\\])*")|(\b(true|false|null)\b)|(-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g, function (match) {
      let cls = 'number';
      if (/^">/.test(match)) {
        if (/^"http/.test(match)) {
          return '<a href="' + match.slice(1, -1) + '" target="_blank" style="color: #4a9ff5;">' + match + '</a>';
        }
        cls = 'string';
      } else if (/true|false/.test(match)) {
        cls = 'boolean';
      } else if (/null/.test(match)) {
        cls = 'null';
      }
      return '<span class="' + cls + '">' + match + '</span>';
    }) + '</pre>';
  }

  // 任务一：查询用户及角色
  $('#userRoleForm').submit(function(e) {
    e.preventDefault();
    const loginname = $('#loginname').val();
    callApi('api/user/withRoles', 'GET', {loginname: loginname}, '#userRoleResult');
  });

  // 任务二：查询角色及菜单
  $('#roleMenuForm').submit(function(e) {
    e.preventDefault();
    const roleId = $('#roleId').val() || null;
    const roleName = $('#roleName').val() || null;

    if (!roleId && !roleName) {
      $('#roleMenuResult').html('<div class="alert alert-warning">请至少输入角色ID或角色名称其中一项</div>');
      return;
    }

    callApi('api/role/withMenus', 'GET', {roleId: roleId, roleName: roleName}, '#roleMenuResult');
  });

  // 任务二：分页查询角色及菜单
  $('#rolesPagingForm').submit(function(e) {
    e.preventDefault();
    const roleId = $('#rolesPageRoleId').val() || null;
    const roleName = $('#rolesPageRoleName').val() || null;
    const status = $('#rolesPageStatus').val() || null;
    const pageNum = $('#rolesPageNum').val();
    const pageSize = $('#rolesPageSize').val();

    callApi('api/role/list', 'GET', {
      roleId: roleId,
      roleName: roleName,
      status: status,
      pageNum: pageNum,
      pageSize: pageSize
    }, '#rolesPagingResult');
  });

  // 任务三：多条件查询用户及权限
  $('#usersSearchForm').submit(function(e) {
    e.preventDefault();
    const loginname = $('#usersSearchLoginname').val() || null;
    const email = $('#usersSearchEmail').val() || null;
    const status = $('#usersSearchStatus').val() || null;
    const pageNum = $('#usersPageNum').val();
    const pageSize = $('#usersPageSize').val();

    callApi('api/user/list', 'GET', {
      loginname: loginname,
      email: email,
      status: status,
      pageNum: pageNum,
      pageSize: pageSize
    }, '#usersSearchResult');
  });

  // 添加CSS样式用于JSON高亮
  $(document.head).append(
          `<style>
            .string { color: #ce9178; font-weight: 500; }
            .number { color: #b5cea8; font-weight: 600; }
            .boolean { color: #569cd6; font-weight: 600; }
            .null { color: #569cd6; font-weight: 600; }
            pre {
                background-color: transparent !important;
                border: none !important;
                margin: 0 !important;
                font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
                line-height: 1.6;
                font-size: 0.9rem;
            }
        </style>`
  );
</script>
</body>
</html>